/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package datagraph.graph.explore;

import java.awt.geom.Point2D;

import ghidra.graph.viewer.vertex.AbstractVisualVertex;

/**
 * A type of VisualVertex that is part of a exploration graph where each vertex (except the root
 * vertex) has a concept of a source vertex that indicates what vertex's edge was first used to add
 * this vertex to the graph. Any vertex in the graph can follow the source vertex and it's source
 * vertex all the way back to the root source vertex. This means that any graph consisting of 
 * {@link EgVertex}s, regardless of its full set of edges, has a natural representation as a tree
 * which is useful for creating a layout that reflects how the tree was generated from a single
 * source seed vertex. 
 */
public abstract class EgVertex extends AbstractVisualVertex {
	protected EgVertex source;
	private boolean userChangedLocation = false;

	/**
	 * Constructor
	 * @param source the vertex from which this vertex was added by following an edge
	 */
	public EgVertex(EgVertex source) {
		this.source = source;
	}

	/**
	 * {@return the vertex that was used to discover this vertex.}
	 */
	public EgVertex getSourceVertex() {
		return source;
	}

	@Override
	public void dispose() {
		// subclasses can override this if they need to perform cleanup
	}

	@Override
	public void setLocation(Point2D location) {
		if (userChangedLocation) {
			return;
		}
		super.setLocation(location);
	}

	/**
	 * Manually sets the location for this vertex.
	 * @param location the location for the vertex
	 */
	public void setUserChangedLocation(Point2D location) {
		userChangedLocation = true;
		super.setLocation(location);
	}

	/**
	 * Clears the user changed location lock, allowing the vertex to get a new location when the
	 * graph is laid out.
	 */
	public void clearUserChangedLocation() {
		userChangedLocation = false;
	}

	/**
	 * {@return true if the user manually set the location. A manually set location ignores 
	 * locations generated by the layout.}
	 */
	public boolean hasUserChangedLocation() {
		return userChangedLocation;
	}

	/**
	 * {@return true if this is the root node for the exploration graph.}
	 */
	public boolean isRoot() {
		return source == null;
	}

	protected void setSource(EgVertex source) {
		this.source = source;
	}

	/**
	 * {@return the point to use for the first point in an edge going to the given end vertex.}
	 * @param end the destination vertex for the edge
	 */
	protected abstract Point2D getStartingEdgePoint(EgVertex end);

	/**
	 * {@return the point to use for the last point in an edge coming from the given start vertex.}
	 * @param start the starting vertex for the edge
	 */
	protected abstract Point2D getEndingEdgePoint(EgVertex start);

	/**
	 * {@return the outgoing offset of the edge from the center of the vertex for the edge ending 
	 * at the given end vertex.}
	 * @param end the destination vertex of the edge to get an outgoing edge offset for
	 */
	protected int getOutgoingEdgeOffsetFromCenter(EgVertex end) {
		return 0;
	}

	/**
	 * {@return the incoming offset of the edge from the center of the vertex from the edge starting 
	 * at the given start vertex.}
	 * @param start the starting vertex of the edge to get an incoming edge offset for
	 */
	protected int getIncomingEdgeOffsetFromCenter(EgVertex start) {
		return 0;
	}

}
